/*
 * Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef VIRTNET_SF_H
#define VIRTNET_SF_H

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <infiniband/verbs.h>
#include <infiniband/mlx5dv.h>

#include "virtnet_vq.h"

#ifdef __cplusplus
extern "C" {
#endif

#define SF_SYS_NAME_LEN		(20)
#define VIRTNET_SF_BASE_ID	(1000)

struct virtnet_device;

struct virtnet_rx_hash_field_select {
	uint32_t l3_prot_type:1;
	uint32_t l4_prot_type:1;
	uint32_t selected_fields:30;
};

struct virtnet_tir_devx_attr {
	uint32_t disp_type:4;
	uint32_t lro_timeout_period_usecs:16;
	uint32_t lro_enable_mask:4;
	uint32_t lro_max_msg_sz:8;
	uint32_t inline_rqn:24;
	uint32_t rx_hash_symmetric:1;
	uint32_t tunneled_offload_en:1;
	uint32_t indirect_table:24;
	uint32_t rx_hash_fn:4;
	uint32_t self_lb_block:2;
	uint32_t transport_domain:24;
	uint32_t rx_hash_toeplitz_key[10];
	struct virtnet_rx_hash_field_select rx_hash_field_selector_outer;
	struct virtnet_rx_hash_field_select rx_hash_field_selector_inner;
};

struct virtnet_tir {
	SLIST_ENTRY(virtnet_tir) next;
	struct virtnet_tir_devx_attr attr;
	uint32_t id;
	void *obj;
	void *action;
};

struct virtnet_rqt {
	uint32_t id;
	struct mlx5dv_devx_obj *obj;
};

struct virtnet_sf_drop {
	struct ibv_cq *cq;
	struct virtnet_rqt rqt;
	struct virtnet_tir *tir;
	void *wqes;
	struct mlx5dv_devx_umem *wqes_umem;
	struct mlx5dv_devx_obj *rq;
	uint32_t rqn;
};

struct rss_flow_list;
struct virtnet_sf_steer {
	struct virtnet_rqt rqt; /* RQTable, used as RSS indirect table. */
	void *rx_domain;
	void *rx_tbl;
	SLIST_HEAD(rss_tir_list, virtnet_tir) rss_tir_list;
	void *promisc_flow;
	void *allmulti_flow;
	void *alluni_flow;
	void *nouni_flow;
	void *nomulti_flow;
	void *nobcast_flow;
	struct rss_flow_list *allbcast_flow; /* Flow entry to allow all
					      * broadcast packets. */
	struct virtnet_sf_drop drop;
};

struct virtnet_flow_table_entry {
	struct mlx5dv_devx_obj *obj;
	uint32_t idx;
	struct virtnet_flow_group *fg; /* point back to belonged fg. */
};

struct virtnet_flow_group {
	SLIST_ENTRY(virtnet_flow_group) next;
	uint32_t id;
	uint32_t start_idx;
	uint32_t end_idx;
	struct virtnet_flow_table *ft; /* point back to beloned ft. */
};

struct virtnet_flow_table {
	struct mlx5dv_devx_obj *obj;
	uint32_t id;
	uint8_t level;
	uint64_t size;
	SLIST_HEAD(, virtnet_flow_group) fg_list;
	struct virtnet_flow_table_entry *ftes;
};

struct virtnet_sf_context {
	struct ibv_context *dev;
	struct ibv_pd *pd;
	struct ibv_comp_channel *channel;
	uint16_t vhca_id;
	void *td;
	uint32_t td_num;
	void *tis;
	uint32_t tis_num;
	struct virtnet_sf_steer steer;

	struct mlxdevm_port *port;
	uint32_t sf_num;
	char sf_sys_name[SF_SYS_NAME_LEN + 1];
	char sf_sys_path[256];
	char rdma_dev_name[IFNAMSIZ];
	char rep_ndev_name[IFNAMSIZ];
};

int virtnet_sf_create(struct virtnet_device *dev);
void virtnet_sf_destroy(struct virtnet_device *dev);
void virtnet_sf_dev_destroy(struct virtnet_device *dev);
int virtnet_sf_start(struct virtnet_device *dev);
void virtnet_sf_stop(struct virtnet_device *dev);

int virtnet_sf_flows_apply(struct virtnet_device *dev);
int virtnet_sf_mac_flow_apply(struct virtnet_device *dev, uint8_t *mac,
			      void **flow);
int virtnet_sf_mac_flow_destroy(struct virtnet_device *dev, void **flow);
int virtnet_sf_vlan_flow_apply(struct virtnet_device *dev, uint16_t vid,
			       void **flow);
int virtnet_sf_vlan_flow_destroy(struct virtnet_device *dev, void **flow);
int virtnet_sf_set_rx_mode(struct virtnet_device *dev);
int virtnet_sf_mq_update(struct virtnet_device *dev, uint16_t mq);

#ifdef __cplusplus
}
#endif

#endif
